/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 *
 */

/** @file
 *
 * @defgroup ble_sdk_srv_lncp Location and Navigation Service Control Point
 * @{
 * @ingroup ble_sdk_srv
 * @brief Location and Navigation Service Control Point module
 *
 * @details This module implements the Location and Navigation Service Control Point behavior.
 */

#ifndef BLE_LN_CTRLPT_H__
#define BLE_LN_CTRLPT_H__

#include "ble_srv_common.h"
#include "sdk_common.h"

#define BLE_LNS_MAX_ROUTE_NAME_LEN (BLE_L2CAP_MTU_DEF - 5)           /**< The maximum length of length of a route name. */
#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */

typedef struct ble_lncp_s ble_lncp_t;

/** @brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */
typedef enum
{
    LNCP_EVT_ELEVATION_SET,     /**< Location and Navigation elevation was set. */
    LNCP_EVT_FIX_RATE_SET,      /**< Fix rate was set. */
    LNCP_EVT_ROUTE_SELECTED,    /**< A route was selected. */
    LNCP_EVT_NAV_COMMAND,       /**< A navigation command was issued. */
    LNCP_EVT_MASK_SET,          /**< Location and Speed feature mask was set. */
    LNCP_EVT_TOTAL_DISTANCE_SET /**< Location and Navigation total distance was set. */
} ble_lncp_evt_type_t;

/** @brief Navigation commands. These commands can be sent to the control point and returned by an event callback. */
typedef enum
{
    LNCP_CMD_NAV_STOP = 0x00,          /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */
    LNCP_CMD_NAV_START = 0x01,         /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
    LNCP_CMD_NAV_PAUSE = 0x02,         /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */
    LNCP_CMD_NAV_CONTINUE = 0x03,      /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
    LNCP_CMD_NAV_SKIP_WAYPOINT = 0x04, /**< When received, is_navigation_running in @ref ble_lns_s will not be affected. */
    LNCP_CMD_NAV_NEAREST = 0x05,       /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
} ble_lncp_nav_cmd_t;
#define LNCP_NAV_CMD_MAX 0x05
#define LNCP_NAV_CMD_LEN (OPCODE_LENGTH + 1)

#if defined(__CC_ARM)
#pragma push
#pragma anon_unions
#elif defined(__ICCARM__)
#pragma language = extended
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif

/** @brief A mask can be used to temporarily enable and disable features of the Location and Speed characteristic.*/
typedef union {
    uint8_t flags;
    struct
    {
        uint8_t instantaneous_speed : 1;
        uint8_t total_distance : 1;
        uint8_t location : 1;
        uint8_t elevation : 1;
        uint8_t heading : 1;
        uint8_t rolling_time : 1;
        uint8_t utc_time : 1;
    };
} ble_lncp_mask_t;

#if defined(__CC_ARM)
#pragma pop
#elif defined(__ICCARM__)
/* leave anonymous unions enabled */
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif

typedef struct
{
    ble_lncp_evt_type_t evt_type;
    union {
        ble_lncp_mask_t mask;
        ble_lncp_nav_cmd_t nav_cmd;
        uint32_t total_distance;
        uint8_t fix_rate;
        uint16_t selected_route;
        uint32_t elevation;
    } params;
} ble_lncp_evt_t;

// Location and Navigation Control Point response values
typedef enum
{
    LNCP_RSP_RESERVED = 0x00,                                                    /**< Reserved for future use. */
    LNCP_RSP_SUCCESS = 0x01,                                                     /**< Success. */
    LNCP_RSP_OP_CODE_NOT_SUPPORTED = 0x02,                                       /**< Op Code not supported. */
    LNCP_RSP_INVALID_PARAMETER = 0x03,                                           /**< Invalid Parameter. */
    LNCP_RSP_OPERATION_FAILED = 0x04,                                            /**< Operation Failed. */
    LNCP_RSP_PROC_ALR_IN_PROG = BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG,     /**< Control point procedure is already in progress. */
    LNCP_RSP_CCCD_CONFIG_IMPROPER = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR /**< CCCD is improperly configured. */
} ble_lncp_rsp_code_t;

typedef ble_lncp_rsp_code_t (*ble_lncp_evt_handler_t)(ble_lncp_t const *p_lncp, ble_lncp_evt_t const *p_evt);

// Location and Navigation Control Point Op Code values
typedef enum
{
    LNCP_OP_RESERVED = 0x00,               /**< Reserved for future use. */
    LNCP_OP_SET_CUMULATIVE_VALUE = 0x01,   /**< Set Cumulative Value. */
    LNCP_OP_MASK_LOC_SPEED_CONTENT = 0x02, /**< Mask Location and Speed Characteristic Content. */
    LNCP_OP_NAV_CONTROL = 0x03,            /**< Navigation Control. */
    LNCP_OP_REQ_NUM_ROUTES = 0x04,         /**< Request Number of Routes. */
    LNCP_OP_REQ_NAME_OF_ROUTE = 0x05,      /**< Request Name of Route. */
    LNCP_OP_SELECT_ROUTE = 0x06,           /**< Select Route. */
    LNCP_OP_SET_FIX_RATE = 0x07,           /**< Set Fix Rate. */
    LNCP_OP_SET_ELEVATION = 0x08,          /**< Set Elevation. */
    LNCP_OP_RESPONSE_CODE = 0x20           /**< Response code. */
} ble_lncp_op_code_t;

/** @brief Location and Navigation Control Point procedure status */
typedef enum
{
    LNCP_STATE_NO_PROC_IN_PROGRESS,  /**< No procedure in progress. */
    LNCP_STATE_INDICATION_PENDING,   /**< Control Point indication is pending. */
    LNCP_STATE_CONFIRMATION_PENDING, /**< Waiting for the indication confirmation. */
} ble_lncp_procedure_status_t;

/** @brief Information included in a control point write response indication. */
typedef struct
{
    ble_lncp_op_code_t op_code;   /**< Opcode of the control point write action. */
    ble_lncp_rsp_code_t rsp_code; /**< Response code of the control point write action. */
    uint8_t rsp_param_len;
    uint8_t rsp_param[MAX_CTRL_POINT_RESP_PARAM_LEN];
} ble_lncp_rsp_t;

typedef struct
{
    uint16_t service_handle;
    ble_lncp_evt_handler_t evt_handler;
    ble_srv_error_handler_t error_handler;

    uint32_t available_features;      /**< Value of the LN feature. */
    bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
    bool is_control_point_present;    /**< If set to true, the control point characteristic will be added. Else not. */
    bool is_navigation_present;       /**< If set to true, the navigation characteristic will be added. Else not. */
    ble_gatts_char_handles_t navigation_handles;

    uint32_t total_distance;
    uint32_t elevation;

    security_req_t write_perm;
    security_req_t cccd_write_perm;
} ble_lncp_init_t;

struct ble_lncp_s
{
    uint16_t conn_handle;
    uint16_t service_handle;
    ble_gatts_char_handles_t ctrlpt_handles;
    ble_gatts_char_handles_t navigation_handles;
    ble_lncp_evt_handler_t evt_handler;
    ble_srv_error_handler_t error_handler;
    ble_lncp_procedure_status_t procedure_status;
    ble_lncp_rsp_t pending_rsp;

    ble_lncp_mask_t mask;
    uint32_t total_distance;
    uint32_t elevation;
    uint8_t fix_rate;
    uint16_t selected_route;
    uint32_t available_features;      /**< Value of the LN feature. */
    bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
    bool is_control_point_present;    /**< If set to true, the control point characteristic will be added. Else not. */
    bool is_navigation_present;       /**< If set to true, the navigation characteristic will be added. Else not. */
    bool is_navigation_running;       /**< This variable can be set using the control point. Must be true to be able to send navigation updates. */

    bool is_ctrlpt_indication_enabled; /**< True if indication is enabled on the Control Point characteristic. */
    bool is_nav_notification_enabled;  /**< True if notification is enabled on the Navigation characteristic. */
};

void ble_lncp_on_ble_evt(ble_lncp_t *p_lncp, ble_evt_t const *p_ble_evt);

uint32_t ble_lncp_total_distance_get(ble_lncp_t const *p_lncp);

uint32_t ble_lncp_elevation_get(ble_lncp_t const *p_lncp);

ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const *p_lncp);

bool ble_lncp_is_navigation_running(ble_lncp_t const *p_lncp);

ret_code_t ble_lncp_init(ble_lncp_t *p_lncp, ble_lncp_init_t const *p_lncp_init);

#endif // BLE_LN_CTRLPT_H__

/** @} */
